﻿/*
Copyright © 2011 François Karman

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

See <license.txt> for the complete license of the software.
*/

using System;
using System.Threading;
using NUnit.Framework.Api;
using NUnit.Framework.Internal;

namespace NUnit.Phone.Gui
{
    /// <summary>
    /// Manages the execution of a unit test suite and
    /// provides events to follow the execution.
    /// </summary>
    /// <remarks>
    /// This class will will execute the tests in a new thread.
    /// </remarks>
    public class TestRunner : ITestListener
    {
        /// <summary>
        /// The base test managed by the runner.
        /// </summary>
        private readonly Test reference;

        /// <summary>
        /// A value indicating whether the runner is already started.
        /// </summary>
        private bool started;

        /// <summary>
        /// Initializes a new instance of the TestRunner class.
        /// </summary>
        /// <param name="reference">
        /// The base test managed by the runner.
        /// </param>
        public TestRunner(Test reference)
        {
            if (reference == null)
            {
                throw new ArgumentNullException("reference");
            }

            this.reference = reference;
        }

        /// <summary>
        /// Gets the base test managed by the runner.
        /// </summary>
        public ITest Test
        {
            get { return this.reference; }
        }

        /// <summary>
        /// Occurs when a test is finished.
        /// </summary>
        public event EventHandler<TestFinishedEventArgs> TestFinished;

        /// <summary>
        /// Occurs when a trace is generated by the tests.
        /// </summary>
        public event EventHandler<TestOutputEventArgs> TestOutput;

        /// <summary>
        /// Occurs when a test is started.
        /// </summary>
        public event EventHandler<TestStartedEventArgs> TestStarted;

        /// <summary>
        /// Starts the test - this execution will be done in a new thread.
        /// </summary>
        public void Start()
        {
            if (this.started)
            {
                return;
            }

            this.started = true;
            Thread thread = new Thread(() => this.reference.Run(this));
            thread.Start();
        }

        /// <summary>
        /// Called when a test is finished.
        /// </summary>
        /// <param name="result">The result of the finished test.</param>
        void ITestListener.TestFinished(ITestResult result)
        {
            if (this.TestFinished != null)
            {
                this.TestFinished(this, new TestFinishedEventArgs(result));
            }
        }

        /// <summary>
        /// Called when a trace is generated by the test.
        /// </summary>
        /// <param name="testOutput">The trace generated.</param>
        void ITestListener.TestOutput(TestOutput testOutput)
        {
            if (this.TestOutput != null)
            {
                this.TestOutput(this, new TestOutputEventArgs(testOutput));
            }
        }

        /// <summary>
        /// Called when a test is started.
        /// </summary>
        /// <param name="test">The started test.</param>
        void ITestListener.TestStarted(ITest test)
        {
            if (this.TestStarted != null)
            {
                this.TestStarted(this, new TestStartedEventArgs(test));
            }
        }
    }
}
